﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DocumentRepository.cs" company="DST Nexdox">
//   Copyright (c) DST Nexdox. All rights reserved.
// </copyright>
// <summary>
//   Defines the DocumentRepository type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace UnityRepository.Repositories
{
  using System;
  using System.Collections.Generic;
  using System.Data.Entity;
  using System.Linq;
  using EFRepository;
  using Entities;
  using Extensions;
  using UnityRepository.Contexts;
  using UnityRepository.Interfaces;

  public class DocumentRepository : BaseEfRepository<Document>, IDocumentRepository
  {
    public DocumentRepository(String connectionString)
      : base(new UnityDbContext(connectionString))
    {
      
    }

    public Document GetDocument(Int32 id)
    {
      return (from d in Entities
              where d.Id == id
              select d).FirstOrDefault();
    }

    public Document GetDocument(String documentId)
    {
      return (from d in this.GetDocumentsIncludingApprovalRejectionCheckOutGridRunAndHouseHoldEntities()
              where d.DocumentId == documentId
              select d).FirstOrDefault();
    }

    public IList<Document> GetDocuments(String grid)
    {
      return (from d in Entities
              where d.GridRun.Grid == grid
              select d).ToList();
    }

    public IList<Document> GetDocumentsIncludingCheckOutEntity(String grid)
    {
      return (from d in this.GetDocumentsIncludingCheckOutEntity() where d.GridRun.Grid == grid select d).ToList();
    }

    public IEnumerable<Document> GetDocuments(IEnumerable<Int32> ids)
    {
      foreach (IEnumerable<Int32> idBatch in ids.Batch(this.BatchSize))
      {
        IEnumerable<Document> documents = this.GetDocumentsViaIdsRequest(idBatch);
        foreach (Document document in documents)
        {
          yield return document;
        }
      }
    }

    public IEnumerable<Document> GetDocuments(IEnumerable<String> documentIds)
    {
      foreach (IEnumerable<String> documentIdBatch in documentIds.Batch(this.BatchSize))
      {
        IEnumerable<Document> documents = this.GetDocumentsViaDocumentIdsRequest(documentIdBatch);
        foreach (Document document in documents)
        {
          yield return document;
        }
      }
    }

    public Int32 GetDocumentsCount(String grid)
    {
      return this.GetDocumentsRequest(grid).Count();
    }

    public IList<Document> GetDocumentsWithApprovalAndRejectionEntities(String grid)
    {
      return (from d in this.GetDocumentsIncludingApprovalAndRejectionEntities()
              where d.GridRun.Grid == grid
              select d).ToList();
    }

    public IList<Document> GetDocumentsIncludingApprovalRejectionAndHouseHoldEntities(String grid)
    {
      return (from d in this.GetDocumentsIncludingApprovalRejectionAndHouseHoldEntities() where d.GridRun.Grid == grid select d).ToList();
    }

    public IList<Document> GetUnApprovedDocuments(String grid)
    {
      return this.GetUnApprovedDocumentsRequest(grid).ToList();
    }

    public Int32 GetUnApprovedDocumentsCount(String grid)
    {
      return this.GetUnApprovedDocumentsRequest(grid).Count();
    }

    public IList<Document> GetApprovedDocuments(String grid)
    {
      return this.GetApprovedDocumentsRequest(grid).ToList();
    }

    public Int32 GetApprovedDocumentsCount(String grid)
    {
      return this.GetApprovedDocumentsRequest(grid).Count();
    }

    public IList<Document> GetApprovedAndNotExported()
    {
      return (from d in this.GetDocumentsIncludingApprovalRejectionCheckOutGridRunAndApplicationEntities()
              where d.Approval != null
                    && d.Export == null
              select d).ToList();
    }

    public IList<KpiReportData> GetDocuments(Int32 mancoId, DateTime startDate, DateTime endDate)
    {
      endDate = endDate.AddHours(23).AddMinutes(59).AddSeconds(59);
      return (from d in Entities
              where
                d.ManCo.Id == mancoId
                && d.GridRun.EndDate >= startDate
                && d.GridRun.EndDate < endDate
              group d by new { DocType = d.DocType.Code, SubDocType = d.SubDocType.Code, d.ManCo } into g
              select new KpiReportData
                              {
                                ManCo = g.Key.ManCo,
                                NumberOfDocs = g.Count(),
                                DocType = g.Key.DocType,
                                SubDocType = g.Key.SubDocType
                              }).ToList();
    }

    public IList<Document> GetDocumentsForBasket(String cartId)
    {
      return this.GetDocumentsForBasketRequest(cartId).ToList();
    }

    private IQueryable<Document> GetDocumentsRequest(String grid)
    {
      return from d in this.Entities where d.GridRun.Grid == grid select d;
    }

    private IEnumerable<Document> GetDocumentsViaIdsRequest(IEnumerable<Int32> ids)
    {
      return
        from d in this.GetDocumentIncludingApprovalRejectionCheckOutManCoAndDocTypeEntities()
        where ids.Contains(d.Id)
        select d;
    }

    private IEnumerable<Document> GetDocumentsViaDocumentIdsRequest(IEnumerable<String> documentIds)
    {
      return
        from d in this.GetDocumentIncludingApprovalRejectionCheckOutManCoAndDocTypeGridRunEntities()
        where documentIds.Contains(d.DocumentId)
        select d;
    }

    private IQueryable<Document> GetApprovedDocumentsRequest(String grid)
    {
      return from d in this.GetDocumentsIncludingApprovalEntity()
             where d.GridRun.Grid == grid && d.Approval != null
             select d;
    }

    private IQueryable<Document> GetUnApprovedDocumentsRequest(String grid)
    {
      return from d in this.GetDocumentsIncludingApprovalAndRejectionEntities()
             where d.GridRun.Grid == grid && d.Approval == null && d.Rejection == null
             select d;
    }

    private IQueryable<Document> GetDocumentsForBasketRequest(String cartId)
    {
      return from d in this.GetDocumentsIncludingApprovalAndRejectionEntities() where d.CartItems.Any(ci => ci.CartId == cartId) select d;
    }

    private IQueryable<Document> GetDocumentsIncludingApprovalEntity()
    {
      return
        this.Entities
          .Include(d => d.Approval);
    }

    private IQueryable<Document> GetDocumentsIncludingCheckOutEntity()
    {
      return
        this.Entities
          .Include(d => d.CheckOut);
    }

    private IQueryable<Document> GetDocumentsIncludingApprovalAndRejectionEntities()
    {
      return
        this.Entities
          .Include(d => d.Approval)
          .Include(d => d.Rejection);
    }

    private IQueryable<Document> GetDocumentsIncludingApprovalRejectionAndHouseHoldEntities()
    {
      return this.Entities
        .Include(d => d.Approval)
        .Include(d => d.Rejection)
        .Include(d => d.HouseHold);
    }

    private IQueryable<Document> GetDocumentsIncludingApprovalRejectionCheckOutGridRunAndHouseHoldEntities()
    {
      return
        this.Entities
          .Include(d => d.Approval)
          .Include(d => d.Rejection)
          .Include(d => d.CheckOut)
          .Include(d => d.GridRun)
          .Include(d => d.HouseHold);
    }

    private IQueryable<Document> GetDocumentsIncludingApprovalRejectionCheckOutGridRunAndApplicationEntities()
    {
      return
        Entities
          .Include(d => d.Approval)
          .Include(d => d.Rejection)
          .Include(d => d.CheckOut)
          .Include(d => d.GridRun)
          .Include(d => d.GridRun.Application);
    }

    private IQueryable<Document> GetDocumentIncludingApprovalRejectionCheckOutManCoAndDocTypeEntities()
    {
      return
        Entities
          .Include(d => d.Approval)
          .Include(d => d.Rejection)
          .Include(d => d.CheckOut)
          .Include(d => d.ManCo)
          .Include(d => d.DocType);
    }

    private IQueryable<Document> GetDocumentIncludingApprovalRejectionCheckOutManCoAndDocTypeGridRunEntities()
    {
      return
        Entities
          .Include(d => d.Approval)
          .Include(d => d.Rejection)
          .Include(d => d.CheckOut)
          .Include(d => d.ManCo)
          .Include(d => d.GridRun);
    }
  }
}
